#include "VSShader.h"
#include "VSGraphicInclude.h"
#include "VSStream.h"
using namespace VSEngine2;
IMPLEMENT_RTTI_NoCreateFun(VSShader,VSBind)
IMPLEMENT_INITIAL_NO_CLASS_FACTORY_BEGIN(VSShader)
IMPLEMENT_INITIAL_NO_CLASS_FACTORY_END
BEGIN_ADD_PROPERTY(VSShader,VSBind)
REGISTER_PROPERTY(m_ResourceName,ResourceName,VSProperty::F_SAVE_LOAD_CLONE)
REGISTER_PROPERTY(m_pUserConstant,UserConstant,VSProperty::F_SAVE_LOAD_CLONE);
REGISTER_PROPERTY(m_pUserSampler,UserSampler,VSProperty::F_SAVE_LOAD_CLONE);
REGISTER_PROPERTY(m_ShaderKey,ShaderKey,VSProperty::F_SAVE_LOAD_CLONE);
REGISTER_PROPERTY(m_Buffer,ShaderBuffer,VSProperty::F_SAVE_LOAD_CLONE);
REGISTER_PROPERTY(m_MainFunName,MainFunName,VSProperty::F_SAVE_LOAD_CLONE);
REGISTER_PROPERTY_DATA(m_pCacheBuffer,m_uiCacheBufferSize,CacheBuffer);
END_ADD_PROPERTY
VSShader::VSShader(const TCHAR * pBuffer,const VSString & MainFunName,bool IsFromFile)
{
	m_pUserConstant.Clear();
	VSMAC_ASSERT(pBuffer);
	if (IsFromFile)
	{
		m_ResourceName = pBuffer;
	}
	else
	{
		m_Buffer = pBuffer;
	}

	m_pCacheBuffer = NULL;
	m_uiCacheBufferSize = 0;
	m_MainFunName = MainFunName;
}
VSShader::VSShader()
{
	m_pCacheBuffer = NULL;
	m_uiCacheBufferSize = 0;
}
VSShader::VSShader(const VSString &Buffer,const VSString & MainFunName,bool IsFromFile)
{
	m_pUserConstant.Clear();
	if (IsFromFile)
	{
		m_ResourceName = Buffer;
	}
	else
	{
		m_Buffer = Buffer;
	}

	m_pCacheBuffer = NULL;
	m_uiCacheBufferSize = 0;
	m_MainFunName = MainFunName;

	
}
VSShader::~VSShader()
{
	VSMAC_DELETEA(m_pCacheBuffer);
	m_uiCacheBufferSize = 0;
	ReleaseResource();
}
void VSShader::SetShaderString(const TCHAR * pBuffer,const VSString & MainFunName,bool IsFromFile)
{
	VSMAC_DELETEA(m_pCacheBuffer);
	m_uiCacheBufferSize = 0;
	ReleaseResource();

	VSMAC_ASSERT(pBuffer);
	if (IsFromFile)
	{
		m_ResourceName = pBuffer;
	}
	else
	{
		m_Buffer = pBuffer;
	}

	m_pCacheBuffer = NULL;
	m_uiCacheBufferSize = 0;
	m_MainFunName = MainFunName;
}
void VSShader::SetShaderString(const VSString &Buffer,const VSString & MainFunName,bool IsFromFile)
{
	VSMAC_DELETEA(m_pCacheBuffer);
	m_uiCacheBufferSize = 0;
	ReleaseResource();

	if (IsFromFile)
	{
		m_ResourceName = Buffer;
	}
	else
	{
		m_Buffer = Buffer;
	}

	m_pCacheBuffer = NULL;
	m_uiCacheBufferSize = 0;
	m_MainFunName = MainFunName;
}
unsigned int VSShader::DiskUse()const
{
	unsigned int Used = VSObject::DiskUse();
	Used += VSResource::DiskUse();
	Used += sizeof(VSUserConstant *) * m_pUserConstant.GetNum();
	Used += sizeof(VSUserSampler *) * m_pUserSampler.GetNum();
	Used += sizeof(unsigned int) * 2;
	Used += m_ShaderKey.DiskUse();
	Used += VSStream::GetStrDistUse(m_Buffer);
	Used += VSStream::GetStrDistUse(m_MainFunName);
	Used += sizeof(unsigned int);
	Used += m_uiCacheBufferSize;
	return Used;
}

bool VSShader::Save(VSStream & rStream,unsigned int &iSaveUse)const
{
	if(!VSBind::Save(rStream,iSaveUse))
		return 0;

	if(!m_ResourceName.GetLength() && !m_Buffer.GetLength())
		return 0;

	if (!VSResource::Save(rStream,iSaveUse))
	{
		return 0;
	}

	unsigned int uiUCNum = m_pUserConstant.GetNum();
	if(!rStream.Write(&uiUCNum,sizeof(unsigned int)))
		return 0;
	iSaveUse += sizeof(unsigned int);

	for(unsigned int i = 0 ; i < uiUCNum ; i++)
	{

		if(!rStream.WriteObjectPtr(m_pUserConstant[i]))
			return 0;
		iSaveUse += sizeof(VSUserConstant *);
	}


	unsigned int uiTexNum = m_pUserSampler.GetNum();
	if(!rStream.Write(&uiTexNum,sizeof(unsigned int)))
		return 0;
	iSaveUse += sizeof(unsigned int);

	for(unsigned int i = 0 ; i < uiTexNum ; i++)
	{

		if(!rStream.WriteObjectPtr(m_pUserSampler[i]))
			return 0;
		iSaveUse += sizeof(VSUserSampler *);
	}
	m_ShaderKey.Save(rStream,iSaveUse);

	

	if(!rStream.WriteString(m_Buffer))
		return 0;
	iSaveUse += VSStream::GetStrDistUse(m_Buffer);

	if (!rStream.WriteString(m_MainFunName))
	{
		return 0;
	}
	iSaveUse += VSStream::GetStrDistUse(m_MainFunName);


	if(!rStream.Write(&m_uiCacheBufferSize,sizeof(unsigned int)))
		return 0;
	iSaveUse += sizeof(unsigned int);

	if (m_pCacheBuffer && m_uiCacheBufferSize)
	{
		if(!rStream.Write(m_pCacheBuffer,m_uiCacheBufferSize))
			return 0;
		iSaveUse += m_uiCacheBufferSize;
	}
	return 1;
}
bool VSShader::Load(VSStream & rStream,unsigned int &iSaveUse)
{
	if(!VSBind::Load(rStream,iSaveUse))
		return 0;

	if (!VSResource::Load(rStream,iSaveUse))
	{
		return 0;
	}
	unsigned int uiUCNum ;
	if(!rStream.Read(&uiUCNum,sizeof(unsigned int)))
		return 0;
	iSaveUse += sizeof(unsigned int);
	m_pUserConstant.SetBufferNum(uiUCNum);

	for(unsigned int i = 0 ; i < uiUCNum ; i++)
	{

		if(!rStream.ReadObjectPtr(m_pUserConstant[i]))
			return 0;
		iSaveUse += sizeof(VSUserConstant *);
	}


	
	unsigned int uiTexNum = 0;
	if(!rStream.Read(&uiTexNum,sizeof(unsigned int)))
		return 0;
	iSaveUse += sizeof(unsigned int);

	m_pUserSampler.SetBufferNum(uiTexNum);

	for(unsigned int i = 0 ; i < uiTexNum ; i++)
	{

		if(!rStream.ReadObjectPtr(m_pUserSampler[i]))
			return 0;
		iSaveUse += sizeof(VSUserSampler *);
	}
	m_ShaderKey.Load(rStream,iSaveUse);

	


	if(!rStream.ReadString(m_Buffer))
		return 0;
	iSaveUse += VSStream::GetStrDistUse(m_Buffer);

	if (!rStream.ReadString(m_MainFunName))
	{
		iSaveUse += VSStream::GetStrDistUse(m_MainFunName);
	}


	if(!rStream.Read(&m_uiCacheBufferSize,sizeof(unsigned int)))
		return 0;
	iSaveUse += sizeof(unsigned int);

	VSMAC_DELETEA(m_pCacheBuffer);
	if (m_uiCacheBufferSize)
	{
		m_pCacheBuffer = VS_NEW unsigned char[m_uiCacheBufferSize];
		if (!m_pCacheBuffer)
		{
			return 0;
		}

		if(!rStream.Read(m_pCacheBuffer,m_uiCacheBufferSize))
			return 0;
		iSaveUse += m_uiCacheBufferSize;
	}
	return 1;
}

bool VSShader::Clone(const VSObject *pObject,unsigned int uiType)
{
	const VSShader* Temp = DynamicCast<VSShader>(pObject); 
	if(!Temp)
		return 0;
	if(!Temp)
		return 0;
	if(!(Temp->GetResourceName().GetLength()) && !Temp->m_Buffer.GetLength())
		return 0;
	if(VSBind::Clone(pObject,uiType) && VSResource::Clone(Temp,uiType))
	{

		m_pUserConstant.Clear();
		m_pUserConstant.SetBufferNum(Temp->m_pUserConstant.GetNum());
		for(unsigned int i = 0 ; i < Temp->m_pUserConstant.GetNum() ; i++)
		{
			VSUserConstant * pTemp1  = Temp->m_pUserConstant[i];
			VSUserConstant * pTemp2 =(VSUserConstant *)VSObject::GetInstance((pTemp1)->GetType().GetName());
			pTemp2->Clone(pTemp1,uiType);
			m_pUserConstant[i] = pTemp2;
		}
		m_pUserSampler.SetBufferNum(Temp->m_pUserSampler.GetNum());
		for(unsigned int i = 0 ; i < Temp->m_pUserSampler.GetNum() ; i++)
		{
			VSUserSampler * pTemp1  = Temp->m_pUserSampler[i];
			VSUserSampler * pTemp2 =(VSUserSampler *)VSObject::GetInstance((pTemp1)->GetType().GetName());
			pTemp2->Clone(pTemp1,uiType);
			m_pUserSampler[i] = pTemp2;
		}
		m_ShaderKey = Temp->m_ShaderKey;

		VSMAC_DELETEA(m_pCacheBuffer);

		m_uiCacheBufferSize = Temp->m_uiCacheBufferSize;
		if (m_pCacheBuffer && m_uiCacheBufferSize)
		{
			m_pCacheBuffer = VS_NEW UCHAR[m_uiCacheBufferSize];
			VSMemcpy(m_pCacheBuffer,Temp->m_pCacheBuffer,m_uiCacheBufferSize);
		}


		m_Buffer = Temp->m_Buffer;

		m_MainFunName = Temp->m_MainFunName;
		return 1;
	}
	else
		return 0;
}
bool VSShader::Link(VSStream & rStream)
{
	if(!VSObject::Link(rStream))
		return 0;
	for(unsigned int i = 0 ; i < m_pUserConstant.GetNum() ; i++)
	{

		rStream.LinkObjectPtr(m_pUserConstant[i]);
		if(!m_pUserConstant[i])
			return 0;
	}


	for(unsigned int i = 0 ; i < m_pUserSampler.GetNum() ; i++)
	{

		rStream.LinkObjectPtr(m_pUserSampler[i]);
		if(!m_pUserSampler[i])
			return 0;
	}
	return 1;

}
bool VSShader::Register(VSStream & rStream)const
{
	if (rStream.IsObjectRegister(this))
	{
		return 1;
	}
	if(!VSObject::Register(rStream))
		return 0;
	for(unsigned int i = 0 ; i < m_pUserConstant.GetNum() ; i++)
	{
		if(m_pUserConstant[i])
		{
			if(!m_pUserConstant[i]->Register(rStream))
				return 0;
		}

	}


	for(unsigned int i = 0 ; i < m_pUserSampler.GetNum() ; i++)
	{
		if(m_pUserSampler[i])
		{
			if(!m_pUserSampler[i]->Register(rStream))
				return 0;
		}

	}
	return 1;
}
// bool VSShader::Bind()
// {
// 	if (!m_pShaderProgram)
// 	{
// 		return false;
// 	}
// 	if (!m_pShaderProgram->m_ConstantDest.GetNum() && !m_pShaderProgram->m_SamplerDesc.GetNum())
// 	{
// 		return false;
// 	}
// 	m_pUserConstant.Clear();
// 	
// 	for (int i = (int)m_pShaderProgram->m_ConstantDest.GetNum() - 1 ; i >= 0 ;i--)
// 	{
// 		VSUserConstant * pConstant = VS_NEW VSUserConstant(m_pShaderProgram->m_ConstantDest[i].m_Name,NULL,1,m_pShaderProgram->m_ConstantDest[i].m_uiValueType,m_pShaderProgram->m_ConstantDest[i].m_uiRegisterCount);
// 		m_pUserConstant.AddElement(pConstant);
// 	}
// 	
// 	
// 	m_pUserSampler.Clear();
// 	
// 	for (int i = (int)m_pShaderProgram->m_SamplerDesc.GetNum() - 1 ; i >= 0  ;i--)
// 	{
// 		VSUserSampler * pSampler = VS_NEW VSUserSampler(m_pShaderProgram->m_SamplerDesc[i].m_Name,m_pShaderProgram->m_SamplerDesc[i].m_uiType);
// 		m_pUserSampler.AddElement(pSampler);
// 	}
// 	
// 	
// 	return true;
// }
bool VSShader::SetParam(const VSUsedName &Name,VSTexAllState * pTexture)
{
	if (!pTexture)
	{
		return false;
	}
	for (unsigned int i = 0 ; i < m_pUserSampler.GetNum() ;i++)
	{
		if (Name == m_pUserSampler[i]->GetName()
			&& pTexture->m_pTex->GetTexType() == m_pUserSampler[i]->GetTexType())
		{
			m_pUserSampler[i]->SetTex(pTexture);
			break;
		}	
	}
	return true;
}
bool VSShader::SetParam(const VSUsedName &Name,void * pDate)
{
	if (!pDate)
	{
		return false;
	}
	for (unsigned int i = 0 ; i < m_pUserConstant.GetNum() ;i++)
	{
		if (Name == m_pUserConstant[i]->GetName())
		{
			void * pConstanDate = m_pUserConstant[i]->GetDate();
			if (!pConstanDate)
			{
				return false;
			}
			VSMemcpy(pConstanDate,pDate,m_pUserConstant[i]->GetSize());
			break;
		}	
	}
	return true;
}
bool VSShader::SetCacheBuffer(void * pBuffer,unsigned int uiSize)
{
	if (!pBuffer || !uiSize)
	{
		return false;
	}
	VSMAC_DELETEA(m_pCacheBuffer);
	m_uiCacheBufferSize = uiSize;
	m_pCacheBuffer = VS_NEW UCHAR[uiSize];
	VSMemcpy(m_pCacheBuffer,pBuffer,uiSize);
	return 1;
}